package ro;
import java.io.*;
import java.util.*;


public class Graph {
	
	private boolean isdirected;
	private String name;
	private String path;
	private String filename; //sans l'extension
	private ArrayList<LinkedList<Cel>> list;
	
	public Graph(String path, String fileName)throws IOException, DotException {
		int i = 0;
		double tmp;
		double tmp2;
		//String val;
		
		if (path.endsWith("/"))
			this.path = path;
		else
			this.path = path+"/";
		
		this.filename = fileName+".dot";
		
		DotParser tok = new DotParser (path+filename);
		
		tok.next();
		
		if(tok.ttype == DotParser.TT_WORD){
			if (tok.sval.equalsIgnoreCase("digraph"))	
				this.isdirected = true;
			else if (tok.sval.equalsIgnoreCase("graph"))
				this.isdirected = false;
			else
				throw new DotException(tok);
		}

		tok.next();
		
		if (tok.ttype == DotParser.TT_WORD)
			this.name = tok.sval;
		else
			throw new DotException(tok);
		
		tok.next();
		
		this.list = new ArrayList<LinkedList<Cel>>();
		
		
		if (tok.ttype != DotParser.TT_LBRACE)
			throw new DotException(tok);
		
		tok.next();
		while(tok.ttype != DotParser.TT_RBRACE){
			switch (tok.ttype){
			
				// Numéro en début de ligne
				case DotParser.TT_NUMBER:
					tmp = tok.nval;
					tok.next();
					//System.out.println("Un tour de boucle en plus !");
					//Cas où on a qu'un numéro et un ; sur la ligne
					if (tok.ttype == DotParser.TT_SEM){
						while(i<=(int)tmp){
							list.add(null);
							i++;
						}
						list.set((int)tmp, new LinkedList<Cel>());
						list.get((int)tmp).add(new Cel((int)tmp));
						tok.next();
					}
					
					else if(tok.ttype == DotParser.TT_COLOR){
						list.add(new LinkedList<Cel>());
						list.get(i).add(new Cel_color(tok.sval ,(int)tmp));
						tok.next();
						if(tok.ttype != DotParser.TT_SEM) throw new DotException(tok);
						tok.next();
					}
					
					//Cas où on a un arc (Test avec isdirected pour renvoyer une erreur si on met -> au lieu de -- et inversement 
					else if ((tok.ttype == DotParser.TT_ARROW && isdirected) || (tok.ttype == DotParser.TT_EDGE && !isdirected)){
						// On passe le -- ou ->
						tok.next();
							
							//Test et ajout dans la liste chaînée du sommet en relation avec le sommet précédent
							if (tok.ttype == DotParser.TT_NUMBER)
								tmp2 = tok.nval;
							else
								throw new DotException(tok);
							
							//On passe au label ou au ;
							tok.next();
							
							//Si on tombe sur un label
							if (tok.ttype == DotParser.TT_LABEL){
								list.get((int)tmp).add(new Cel_label((int)tok.nval,(int)tmp2));
								tok.next();
								
								if(tok.ttype != DotParser.TT_SEM)
									throw new DotException(tok);
							}
							else if (tok.ttype == DotParser.TT_SEM){
								list.get((int)tmp).add(new Cel((int) tmp2));
							}
							
							else{
								throw new DotException(tok);
							}
							
							
							//Si on a pas de label et qu'on est à la fin de la ligne
							
							
							tok.next();
					}
					else
						throw new DotException(tok);
						
					break;
				
				default:
					break;
			}
		}

	}
	
	public int getSize(){
		return list.size();
	}
	
	public ArrayList<Edge> getArete(){
		ArrayList<Edge> result = new ArrayList<Edge>();
		int src;
		
		for(LinkedList<Cel> l : list){
			src = l.get(0).vertex;
			for(Cel c : l){
				if(c.vertex != src){
					if(c.getClass() == Cel_label.class){
						result.add(new Edge(src,((Cel_label)c).label,c.vertex));
					}
					else{
						System.out.println("Erreur: Ce n'est pas un graphe labele.");
						return null;
					}
				}
			}
		}
		
		return result;
	}
	
	public String toString(){
		String result = new String();
		if(isdirected)
			result = "digraph "+this.name+"{\n";
		else
			result = "graph "+this.name+"{\n";

		for(LinkedList<Cel> l : list){
			result = result + l.get(0).toString()+";\n";

			for(Cel c : l){
				if(!l.get(0).equals(c)){
					result=result+l.get(0).toString(); //J'affiche le sommet origine des aretes / arcs
					if(isdirected)
						result=result + "->";
					else
						result = result + "--";
					result = result + c.toString()+";\n";
				}
			}
		}
		
		return result+"}";
	}
	
	public boolean createDot(String nom){
		File file=new File(this.path + nom );
		try {
			file.createNewFile();
			FileWriter fw = null;
			// écriture du graphe dans le fichier
			fw = new FileWriter(file);
			fw.write(this.toString());
			fw.close();
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	/* Classe à terminer doit être modulaire ! */
	private class Cel {
		protected int vertex; //N° du sommet extrêmité d'une arrête
		
		public Cel(int vertex){
			this.vertex = vertex;
		}
		
		public String toString(){
				
			return vertex+"";
		}
	}
	
	private class Cel_label extends Cel{
		private int label;
		
		public Cel_label(int label, int vertex){
			super(vertex);
			this.label = label;
		}
		
		public String toString(){
			return super.toString()+"[label="+label+"]";
		}
	}
	
	private class Cel_color extends Cel{
		private String color;
		
		public Cel_color(String color, int vertex){
			super(vertex);
			this.color = color;
		}
		
		public String toString(){
			return super.toString()+"[color="+color+"]";
		}
	}
	
	private class Cel_flow extends Cel{
		private int utilisation;
		private int capacite;
		
		public Cel_flow(int vertex, String s){
			super(vertex);
			//Récupère la chaîne de caractères avant le / et la convertit en int
			utilisation = Integer.parseInt(s.substring(0, s.indexOf("/"))); 
			//Récupère la chaîne de caractères après le / et la convertit en int
			capacite = Integer.parseInt(s.substring(s.indexOf("/")));		
		}
		
		public String toString(){
			return super.toString()+"["+utilisation+"/"+capacite+"]";
		}
	}
	
}
